package com.clusterswisdom.horn.api.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.clusterswisdom.horn.api.ioc.api.ParamType;
import com.clusterswisdom.horn.api.ioc.struct.DestField;
import com.clusterswisdom.horn.api.ioc.struct.StructConfig;
import com.clusterswisdom.horn.api.ioc.struct.StructDest;

public class DefaultStructMeger implements StructMeger {

	@Override
	public Object megerStruct(Connection conn, StructConfig struct, JSONObject data) throws SQLException {
		StructDest destConfig = struct.getDest();
		String pkValue = (String)data.get(destConfig.getPkField());
		
		Object fetchValue = getPkValue(conn, destConfig, pkValue);
		if (fetchValue == null) {
			return insertStruct(conn, destConfig, data);
			
		} else {
			return updateStruct(conn, destConfig, data);
			
		}
	}
	
	protected Object insertStruct(Connection conn, StructDest dest, JSONObject data) throws SQLException {
		List<String> fields = new ArrayList<String>();
		String insertSql = builderInserSql(fields, dest, data);
		PreparedStatement statement = conn.prepareStatement(insertSql);
		
		for (int i = 0; i < fields.size(); i++) {
			Object fieldValue = data.get(fields.get(i));
			if (fieldValue instanceof String) {
				statement.setString(i + 1, (String)fieldValue);
				
			} else if (fieldValue instanceof Date) {
				java.sql.Date sqlDate = new java.sql.Date(((Date)fieldValue).getTime());
				statement.setDate(i + 1, sqlDate);
				
			}
		}
		
		return statement.executeUpdate();
	}
	
	protected Object updateStruct(Connection conn, StructDest dest, JSONObject data) throws SQLException {
		List<String> fields = new ArrayList<String>();
		String updateSql = builderUpdateSql(fields, dest, data);
		PreparedStatement statement = conn.prepareStatement(updateSql);
		for (int i = 0; i < fields.size(); i++) {
			Object fieldValue = data.get(fields.get(i));
			if (fieldValue instanceof String) {
				statement.setString(i + 1, (String)fieldValue);
				
			} else if (fieldValue instanceof Date) {
				java.sql.Date sqlDate = new java.sql.Date(((Date)fieldValue).getTime());
				statement.setDate(i + 1, sqlDate);
				
			}
		}
		
		statement.executeUpdate();
		return data.get(dest.getPkField());
	}
	
	protected Object getPkValue(Connection conn, StructDest dest, String pkValue) throws SQLException {
		StringBuilder sqlBuilder = new StringBuilder(100);
		sqlBuilder.append("select * from ");
		sqlBuilder.append(dest.getTable()).append(" where ").append(dest.getPkField()).append(" = ?");
		
		PreparedStatement statement = conn.prepareStatement(sqlBuilder.toString());
		statement.setString(1, pkValue);
		
		Object selectedValue = null;
		ResultSet resultSet = statement.executeQuery();
		while (resultSet.next()) {
			selectedValue = resultSet.getString(1);
		}
		
		return selectedValue;
	}
	
	protected String builderInserSql(List<String> insertFields, StructDest dest, JSONObject data) {
		StringBuilder fieldBuilder = new StringBuilder(100);
		StringBuilder valueBuilder = new StringBuilder(100);
		
		String separator = "";
		for (DestField field : dest.getFields()) {
			if (ParamType.STRUCTFIELDS == field.getType() 
					|| ParamType.BYTEARRAY == field.getType() 
					|| ParamType.LIST == field.getType()
					|| data.get(field.getName()) == null) {
				continue;
			}
			
			fieldBuilder.append(separator);
			fieldBuilder.append(field.getName()).append(" ");
			
			valueBuilder.append(separator);
			valueBuilder.append("? ");
			
			separator = ","; 
			insertFields.add(field.getName());
		}
		
		StringBuilder builder = new StringBuilder(100);
		builder.append("insert into ").append(dest.getTable());
		builder.append(" ( ").append(fieldBuilder.toString()).append(") values (");
		builder.append(valueBuilder.toString()).append(")");
		
		return builder.toString();
	}
	
	protected String builderUpdateSql(List<String> updateFields, StructDest dest, JSONObject data) {
		StringBuilder fieldBuilder = new StringBuilder(100);
		
		String separator = "";
		for (DestField field : dest.getFields()) {
			if (ParamType.STRUCTFIELDS == field.getType() 
					|| ParamType.BYTEARRAY == field.getType() 
					|| ParamType.LIST == field.getType()) {
				continue;
			}
			
			fieldBuilder.append(separator);
			
			if (data.get(field.getName()) == null) {
				fieldBuilder.append(field.getName()).append(" = null " );
				
			} else {
				fieldBuilder.append(field.getName()).append(" = ? " );
				updateFields.add(field.getName());
				
			}
			
			separator = ","; 
		}
		
		StringBuilder builder = new StringBuilder(100);
		builder.append("update ").append(dest.getTable());
		builder.append(" set ").append(fieldBuilder.toString()).append(" where ");
		builder.append(dest.getPkField()).append(" = ").append(data.get(dest.getPkField()));
		
		return builder.toString();
	}
}